package data.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import data.ProjectDataProvider;
import data.TreeViewElement;
import data.model.effort.CurrentEffort;
import data.model.effort.DeltaEffort;
import data.model.effort.EstimatedEffort;

/**
 * Status eines Projekts in einer Woche
 * 
 * @author: markus
 */
public class ProjectWeek extends AbstractModel implements Serializable,
		TreeViewElement, ProjectDataProvider {
	private static final long serialVersionUID = 3883492700482673767L;

	private final Project project;
	private final int weekNumber;
	private final Set<Process> processes;
	private final Set<Developer> developers;
	private final ProjectWeek previousWeek;

	private final ProjectCharacteristics projectCharacteristics;
	private final CurrentEffort currentEffort;
	private final DeltaEffort deltaEffort;
	private final EstimatedEffort estimatedEffort;

	/**
	 * @param project
	 * @param weekNumber
	 * @param numberOfTasks
	 * @param numberOfBugs
	 * @param linesOfCode
	 * @param numberOfComponents
	 * @param numberOfTestCases
	 * @param percentageOfSuccessfulTests
	 * @param percentageOfCodeCoverage
	 * @throws IllegalArgumentException
	 *             falls project null
	 */
	public ProjectWeek(Project project, int weekNumber, int numberOfTasks,
			int numberOfBugs, int linesOfCode, int numberOfComponents,
			int numberOfTestCases, double percentageOfSuccessfulTests,
			double percentageOfCodeCoverage) throws IllegalArgumentException {
		super();
		if (project == null) {
			throw new IllegalArgumentException("project must not be null");
		}
		this.project = project;
		this.weekNumber = weekNumber;
		this.projectCharacteristics = new ProjectCharacteristics(numberOfTasks,
				numberOfBugs, linesOfCode, numberOfComponents,
				numberOfTestCases, percentageOfSuccessfulTests,
				percentageOfCodeCoverage);
		this.processes = new LinkedHashSet<Process>();
		this.developers = new LinkedHashSet<Developer>();
		this.deltaEffort = new DeltaEffort(this.processes);
		if (weekNumber == 1) {
			this.previousWeek = null;
			this.currentEffort = new CurrentEffort(null, deltaEffort);
			this.estimatedEffort = new EstimatedEffort(this);
		} else {
			assert (project.getProjectWeek(weekNumber - 1) != null);
			this.previousWeek = project.getProjectWeek(weekNumber - 1);
			this.currentEffort = new CurrentEffort(
					previousWeek.getCurrentEffort(), deltaEffort);
			this.estimatedEffort = new EstimatedEffort(this);
		}

		this.project.addProjectWeek(this);
		addEstimatedEffordPropertyChangeListenerToDevelopers();
	}

	private void addEstimatedEffordPropertyChangeListenerToDevelopers() {
		for (ProjectDeveloper projectDeveloper : getInvolvedDevelopers()) {
			projectDeveloper.getEstimatedEffort().addPropertyChangeListener(
					this.estimatedEffort);
		}
	}

	/**
	 * @return das Project
	 */
	public Project getProject() {
		return project;
	}

	/**
	 * @return die Wochennummer (beginnend bei 1)
	 */
	public int getWeekNumber() {
		return weekNumber;
	}

	/**
	 * @return the numberOfTasks
	 */
	@Override
	public int getNumberOfTasks() {
		return projectCharacteristics.getNumberOfBugs();
	}

	/**
	 * @param numberOfTasks
	 *            the numberOfTasks to set
	 */
	public void setNumberOfTasks(int numberOfTasks) {
		projectCharacteristics.setNumberOfTasks(numberOfTasks);
	}

	/**
	 * @return the numberOfBugs
	 */
	@Override
	public int getNumberOfBugs() {
		return projectCharacteristics.getNumberOfBugs();
	}

	/**
	 * @param numberOfBugs
	 *            the numberOfBugs to set
	 */
	public void setNumberOfBugs(int numberOfBugs) {
		projectCharacteristics.getNumberOfBugs();
	}

	/**
	 * @return the linesOfCode
	 */
	@Override
	public int getLinesOfCode() {
		return projectCharacteristics.getLinesOfCode();
	}

	/**
	 * @param linesOfCode
	 *            the linesOfCode to set
	 */
	public void setLinesOfCode(int linesOfCode) {
		projectCharacteristics.setLinesOfCode(linesOfCode);
	}

	/**
	 * @return the numberOfComponents
	 */
	@Override
	public int getNumberOfComponents() {
		return projectCharacteristics.getNumberOfComponents();
	}

	/**
	 * @param numberOfComponents
	 *            the numberOfComponents to set
	 */
	public void setNumberOfComponents(int numberOfComponents) {
		projectCharacteristics.setNumberOfComponents(numberOfComponents);
	}

	/**
	 * @return the numberOfTestCases
	 */
	@Override
	public int getNumberOfTestCases() {
		return projectCharacteristics.getNumberOfTestCases();
	}

	/**
	 * @param numberOfTestCases
	 *            the numberOfTestCases to set
	 */
	public void setNumberOfTestCases(int numberOfTestCases) {
		projectCharacteristics.setNumberOfTestCases(numberOfTestCases);
	}

	/**
	 * @return the percentageOfSuccessfulTests
	 */
	@Override
	public double getPercentageOfSuccessfulTests() {
		return projectCharacteristics.getPercentageOfSuccessfulTests();
	}

	/**
	 * @param percentageOfSuccessfulTests
	 *            the percentageOfSuccessfulTests to set
	 */
	public void setPercentageOfSuccessfulTests(
			double percentageOfSuccessfulTests) {
		projectCharacteristics
				.setPercentageOfSuccessfulTests(percentageOfSuccessfulTests);
	}

	/**
	 * @return the percentageOfCodeCoverage
	 */
	@Override
	public double getPercentageOfCodeCoverage() {
		return projectCharacteristics.getPercentageOfCodeCoverage();
	}

	/**
	 * @param percentageOfCodeCoverage
	 *            the percentageOfCodeCoverage to set
	 */
	public void setPercentageOfCodeCoverage(double percentageOfCodeCoverage) {
		projectCharacteristics
				.setPercentageOfCodeCoverage(percentageOfCodeCoverage);
	}

	/**
	 * @return the processes
	 */
	Collection<Process> getProcesses() {
		return processes;
	}

	/**
	 * adds the process
	 * 
	 * @param process
	 */
	void addProcess(Process process) {
		processes.add(process);
		addDeveloper(process.getDeveloper());
		// process.addPropertyChangeListener(this);
		process.addPropertyChangeListener(deltaEffort);
	}

	private void addDeveloper(Developer developer) {
		developers.add(developer);
		project.addDeveloper(developer);
	}

	@Override
	public String getText() {
		return Integer.toString(getWeekNumber());
	}

	public boolean isDataComplete() {
		for (Process process : processes) {
			if (process.isDataComplete() == false) {
				return false;
			}
		}
		return true;
	}

	public Set<Developer> getDevelopers() {
		return developers;
	}

	@Override
	public Collection<? extends TreeViewElement> getChildren() {
		return null;
	}

	@Override
	public List<ProjectDeveloper> getInvolvedDevelopers() {
		// TODO: korrekt krass korrigieren ProjectWeekDeveloper
		return new ArrayList<ProjectDeveloper>(
				this.project.getInvolvedDevelopers());
	}

	@Override
	public List<ProjectWeek> getProjectWeeks() {
		return project.getProjectWeeks().subList(0, weekNumber);
	}

	@Override
	public CurrentEffort getCurrentEffort() {
		return currentEffort;
	}

	@Override
	public EstimatedEffort getEstimatedEffort() {
		return estimatedEffort;
	}

	public DeltaEffort getDeltaEffort() {
		return deltaEffort;
	}

	/*
	 * @Override public void propertyChange(PropertyChangeEvent evt) {
	 * System.out.println(this.getClass() + ": " + evt.getSource() + " --- " +
	 * evt.getPropertyName()); if (evt.getSource() instanceof Process) { if
	 * ("estimatedEffort".equals(evt.getPropertyName())) {
	 * firePropertyChange("estimatedEffort", null, getEstimatedEffort()); } else
	 * { firePropertyChange("currentEffort", null, getCurrentEffort());
	 * firePropertyChange("deltaEffort", null, getDeltaEffort()); } } }
	 */
}
